/*************************************************************************
 * All portions of code are copyright by their respective author/s.
 * Copyright (C) 2009      Bryan Christ <bryan.christ@hp.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *----------------------------------------------------------------------*/

#include <stdlib.h>
#include <string.h>

#include "macros.h"
#include "ps_task.h"

ps_task_t* ps_task_create(PSTHREAD callback,void *anything)
{
	ps_task_t	*task;

	if(callback == NULL) return NULL;

	task=(ps_task_t*)calloc(1,sizeof(ps_task_t));
	task->callback=callback;
	task->anything=anything;

	return task;
}

ps_task_t* ps_task_fetch(ps_task_t *node,int16_t offset)
{
	int16_t  i;
	int16_t	delta;

	if(node == NULL) return NULL;

	delta=ABSINT(offset);
	for(i=0;i < delta;i++)
	{
		if(offset < 0)
		{
			if(node->prev == NULL) break;
			node=node->prev;
			continue;
		}

		if(node->next == NULL) break;
		node=node->next;
	}

	return node;
}

void ps_task_swap(ps_task_t *node1,ps_task_t *node2)
{
	if(node1 == NULL || node2 == NULL) return;

	node1->next=node2->next;
	node2->prev=node1->prev;
	node1->prev=node2;
	node2->next=node1;

	if(node1->next!=NULL) node1->next->prev=node1;
	if(node2->prev!=NULL) node2->prev->next=node2;

	return;
}

void ps_task_append(ps_task_t *task,ps_task_t *node,int16_t offset)
{
	if(node == NULL || task == NULL) return;

	if(offset > 0) node=ps_task_fetch(node,offset);

	task->head=node->head;
	task->next=node->next;
	task->prev=node;
	node->next=task;

	if(task->next!=NULL) task->next->prev=task;

	return;
}

void ps_task_prepend(ps_task_t *task,ps_task_t *node,int16_t offset)
{
	if(node == NULL || task == NULL) return;

	if(offset > 0) node=ps_task_fetch(node,offset);

	task->head=node->head;
	task->prev=node->prev;
	task->next=node;
	node->prev=task;

	if(task->prev != NULL) task->prev->next=task;

	return;
}

void ps_task_move(ps_task_t *task,int16_t offset)
{
	ps_task_t	*copy;

	if(offset == 0) return;

	copy=calloc(1,sizeof(ps_task_t));
	memcpy(copy,task,sizeof(ps_task_t));

	if(offset < 1) ps_task_append(copy,task,offset);
	else ps_task_prepend(copy,task,offset);

	ps_task_unlink(task);
	ps_task_destroy(task);

	return;
}

void ps_task_unlink(ps_task_t *task)
{
	if(task == NULL) return;

	if(task->prev!=NULL) task->prev->next=task->next;
	if(task->next!=NULL) task->next->prev=task->prev;

	return;
}

void ps_task_destroy(ps_task_t *task)
{
	if(task == NULL) return;

	free(task);

	return;
}
